package com.fallenpanda.widget.library.calendarview;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.fallenpanda.widget.library.R;
import com.fallenpanda.widget.library.view.ExpandableHeightGridView;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;

/**
 * @since Jan 8 2014 
 * @author Mustafa Ferhan Akman
 */

public class CalendarView extends LinearLayout{

	private static final String TODAY = "today";
    //Get start day of Week. Default calendar first column is SUNDAY
    private static final int SUNDAY = 1;
    private static final int START_DAY_OF_WEEK = 1;

    private Calendar month;
	private CalendarAdapter calendaradapter;

	private Handler handler;
	private ExpandableHeightGridView gridview;
	private String currentSelectedDate;
	private String initialDate;
	private View view;
	private Locale locale;

    private GridView weekdayGridView;

	onCalendarViewListener calendarListener;

	public CalendarView(Context context) {
		super(context);
		init(context);
	}


	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public CalendarView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	public CalendarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	void init(Context context){
		LayoutInflater li = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		view = li.inflate(R.layout.calendar_view, null, false);

		month = Calendar.getInstance();

		month.setTimeInMillis(Util.dateToLong(getInitialDate()));

		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Util.getLocale());
		currentSelectedDate = df.format(month.getTime());

		calendaradapter = new CalendarAdapter(context, month);

		gridview = (ExpandableHeightGridView) view.findViewById(R.id.gridview);
		gridview.setAdapter(calendaradapter);

		handler = new Handler();
		handler.post(calendarUpdater);

		TextView title = (TextView) view.findViewById(R.id.title);

		title.setText(getMonthTitleTextView(month));

		Button previous = (Button) view.findViewById(R.id.previous);

		previous.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setPreviousMonth();
				refreshCalendar();
			}
		});

        Button next = (Button) view.findViewById(R.id.next);
		next.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setNextMonth();
				refreshCalendar();
			}
		});

        weekdayGridView = (GridView) view.findViewById(R.id.weekday_gridview);
        WeekdayArrayAdapter weekdaysAdapter = new WeekdayArrayAdapter(context, R.layout.calendar_item_week, getDaysOfWeek());
        weekdayGridView.setAdapter(weekdaysAdapter);

		gridview.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {

				currentSelectedDate = CalendarAdapter.dayString.get(position);

				String[] separatedTime = currentSelectedDate.split("-");
				String gridvalueString = separatedTime[2].replaceFirst("^0*",
						"");// taking last part of date. ie; 2 from 2012-12-02.
				int gridvalue = Integer.parseInt(gridvalueString);
				// navigate to next or previous month on clicking offdays.
				if ((gridvalue > 10) && (position < 8)) {
					setPreviousMonth();
					refreshCalendar();
				} else if ((gridvalue < 15) && (position > 28)) {
					setNextMonth();
					refreshCalendar();
				}
				((CalendarAdapter) parent.getAdapter()).setSelected(v);

				month.setTimeInMillis(Util.dateToLong(currentSelectedDate));
				calendaradapter.initCalendarAdapter(month, calendarListener);

				if (calendarListener != null) 
					calendarListener.onDateChanged(currentSelectedDate);
			}
		});
		
		gridview.setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view,
					int position, long id) {
				if (calendarListener != null) 
					calendarListener.onDateLongClick(CalendarAdapter.dayString.get(position));
				return false;
			}
			
		});

		addView(view);
	}

	protected void setNextMonth() {
		if (month.get(Calendar.MONTH) == 
				month.getActualMaximum(Calendar.MONTH)) {
			
			month.set((month.get(Calendar.YEAR) + 1),
					month.getActualMinimum(Calendar.MONTH), 1);
			
		} else {
			month.set(Calendar.MONTH,
					month.get(Calendar.MONTH) + 1);
		}
	}

	protected void setPreviousMonth() {
		if (month.get(Calendar.MONTH) == month
				.getActualMinimum(Calendar.MONTH)) {
			month.set((month.get(Calendar.YEAR) - 1),
					month.getActualMaximum(Calendar.MONTH), 1);
		} else {
			month.set(Calendar.MONTH,
					month.get(Calendar.MONTH) - 1);
		}

	}

	protected void showToast(String string) {
		Toast.makeText(getContext(), string, Toast.LENGTH_SHORT).show();
	}

	public int getSelectedMonth(){
		return month.get(Calendar.MONTH) + 1;
	}

	public int getSelectedYear(){
		return month.get(Calendar.YEAR);
	}

	public void refreshCalendar() {

		TextView title = (TextView) view.findViewById(R.id.title);

		calendaradapter.refreshDays();
		//calendaradapter.notifyDataSetChanged();
		handler.post(calendarUpdater); 

		title.setText(getMonthTitleTextView(month));

		if (calendarListener != null) {
			calendarListener.onDisplayedMonthChanged(
					month.get(Calendar.MONTH) + 1, 
					month.get(Calendar.YEAR), 
					(String) DateFormat.format("MMMM", month));
		}

	}

	public Runnable calendarUpdater = new Runnable() {

		@Override
		public void run() {

			gridview.setExpanded(true);
			calendaradapter.notifyDataSetChanged();
		}
	};

	public void setOnCalendarViewListener(onCalendarViewListener c){
		calendarListener = c;
	}

	public String getInitialDate(){
		if (initialDate == null) {
			return Util.getCurrentDate();
		}
		return initialDate;
	}

	/**
	 * @date "yyyy-MM-dd"
	 * */
	public void setDate(String date){
		if (date.equals(CalendarView.TODAY)) {
			initialDate = Util.getCurrentDate();
		}
		else{
			initialDate = date;
		}

		initialDate = date;
		currentSelectedDate = date;
		month.setTimeInMillis(Util.dateToLong(date));
		calendaradapter.initCalendarAdapter(month, calendarListener);

	}

	public String getSelectedDate(){
		return currentSelectedDate;
	}

	/**
	 * @param dates like this format: "2014-01-15"
	 * */
	public void setEvents(ArrayList<String> dates){
		calendaradapter.setItems(dates);
		handler.post(calendarUpdater);
	}

    /**
     * Flags to display month
     */
    private static final int MONTH_YEAR_FLAG = DateUtils.FORMAT_SHOW_DATE
            | DateUtils.FORMAT_NO_MONTH_DAY | DateUtils.FORMAT_SHOW_YEAR;

    /**
     * Reuse formatter to print "MMMM yyyy" format
     */
    private final StringBuilder monthYearStringBuilder = new StringBuilder(50);
    private Formatter monthYearFormatter = new Formatter(monthYearStringBuilder, Util.getLocale());

    /**
     * get month title text
     */
    protected String getMonthTitleTextView(Calendar month) {
        // Refresh title view
        long millis = month.getTimeInMillis();

        // This is the method used by the platform Calendar app to get a
        // correctly localized month name for display on a wall calendar
        monthYearStringBuilder.setLength(0);
        String monthTitle = DateUtils.formatDateRange(getContext(),
                monthYearFormatter, millis, millis, MONTH_YEAR_FLAG).toString();

        return monthTitle;
    }

    /**
     * To display the week day title
     *
     * @return "SUN, MON, TUE, WED, THU, FRI, SAT"
     */
    protected ArrayList<String> getDaysOfWeek() {
        ArrayList<String> list = new ArrayList<String>();

        SimpleDateFormat fmt = new SimpleDateFormat("EEE", Util.getLocale());

        // 17 Feb 2013 is Sunday
        Calendar sunday = Calendar.getInstance();
        sunday.set(2013, Calendar.FEBRUARY, 17, 0, 0, 0);
        Calendar nextDay = (Calendar) sunday.clone();
        nextDay.add(Calendar.DAY_OF_MONTH, START_DAY_OF_WEEK - SUNDAY);

        for (int i = 0; i < 7; i++) {
            Date date = nextDay.getTime();
            list.add(fmt.format(date).toUpperCase());
            nextDay.add(Calendar.DAY_OF_MONTH, 1);
        }

        return list;
    }

}
